﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting.Channels;
using System.Collections;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting;
using DrawerGeneral;
using Drawer.Controls;

namespace DrawerServer
{
    public partial class ServerForm : Form
    {
        /// <summary>
        /// Hashtable of WrapperTransporterClass used to send message to client.
        /// Hashtable'key is client name string which is stored in ConnectingClientList
        /// </summary>
        public Hashtable ToClientChannels;

        /// <summary>
        /// Containing the name of clients who are connecting to server
        /// </summary>
        public List<String> ConnectingClientList { get; private set; }

        /// <summary>
        /// Map between client's element index and server's element index
        /// </summary>
        public Hashtable IndexMap { get; private set; }

        /// <summary>
        /// Canvas to draw
        /// </summary>
        public DrawCanvas DrawCanvas;// { get; private set; }

        public int DrawCanvasChildrenCount;

        public int ServerPort = 4672;

        /// <summary>
        /// Initialize ServerForm and make server listen to connection from client in port 6123
        /// </summary>
        public ServerForm()
        {
            InitializeComponent();

            DrawCanvas = new DrawCanvas();
            DrawCanvasHost.Child = DrawCanvas;

            ConnectingClientList = new List<string>();
            ToClientChannels = new Hashtable();
            IndexMap = new Hashtable();
            DrawCanvasChildrenCount = 0;
            // Technique to use delegate -----------------

            BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
            BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
            IDictionary props = new Hashtable();
            props["port"] = ServerPort;
            props["typeFilterLevel"] = TypeFilterLevel.Full;
            HttpChannel chan = new HttpChannel(props, clientProvider, serverProvider);
            ChannelServices.RegisterChannel(chan, false);
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject), "RemoteObject.soap", WellKnownObjectMode.SingleCall);
            AppendTextToDisplay("Listening in port " + ServerPort + "...");

            // --------------------------------------------
        }

        /// <summary>
        /// Do nothing callback, use in asynchrous remote method calling.
        /// When the method return, this function will be called.
        /// </summary>
        /// <param name="res"></param>
        public void DoNothingCallback(IAsyncResult res)
        { }

        /// <summary>
        /// Add text to the server display
        /// </summary>
        /// <param name="content"></param>
        delegate void tmp(string content);
        public void AppendTextToDisplay(string Content)
        {
            //this.txtActivities.AppendText(Environment.NewLine + "# " + Content + Environment.NewLine);
            //if (this.InvokeRequired)
            //{
            //    tmp a = new tmp(AppendTextToDisplay);
            //    this.Invoke(a, Content);
            //}
            //else
            //{
            //    this.txtActivities.AppendText(Environment.NewLine + "# " + Content + Environment.NewLine);
            //}
        }

        /// <summary>
        /// Handling the event of clicking button Send, which means send a message to all connecting
        /// clients
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            //walk through the list of connecting clients
            foreach (String ClientNameString in ServerStartup.sf.ConnectingClientList)
            {
                // get the WrapperTransporterClass corresponding to each client
                // and use these wrapper class to send message to client
                Notify((WrapperTransporterClass)ServerStartup.sf.ToClientChannels[ClientNameString], this.txtMsg.Text);
            }
        }
        /// <summary>
        /// Send the message msg to the client associated with the WrapperTransporterClass ToClientWTC
        /// This method will create a sub-thread which take the responsibility of calling remote method
        /// at client side, waiting for returning, and call DoNothingCallback when is returned.
        /// </summary>
        /// <param name="ToClientWTC">Wrapper class which contains methods to talk with client</param>
        /// <param name="msg">content of the message</param>
        public void Notify(WrapperTransporterClass ToClientWTC, String msg)
        {
            DelegateSendMessageToClientTransporter g = new DelegateSendMessageToClientTransporter(ToClientWTC.RunSendMessageToClientTransporter);
            g.BeginInvoke(msg, new AsyncCallback(DoNothingCallback), null);
        }
    }
}
